﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Ionic.Zip;

namespace XUtility
{
    public abstract class FileClass
    {
        #region 在结尾追加分隔符
        /// <summary>
        /// 在结尾追加分隔符，避免某些文件夹路径忘记加斜杠，导致出错
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static String AdditionalDelimiter(String path)
        {
            if (path.HasValue() && !path.EndsWith(@"\"))
                path += @"\";
            return path;
        }
        #endregion

        /// <summary>
        /// 获取目录中的所有文件的大小
        /// </summary>
        public static Int64 GetDirectoryLength(String dirPath)
        {
            //判断给定的路径是否存在,如果不存在则退出
            if (!Directory.Exists(dirPath))
                return 0;
            Int64 len = 0;

            DirectoryInfo di = new DirectoryInfo(dirPath);
            foreach (FileInfo fi in di.GetFiles())
            {
                len += fi.Length;
            }

            //获取中所有的文件夹,并存到一个新的对象数组中,以进行递归
            DirectoryInfo[] dis = di.GetDirectories();
            if (dis.Length > 0)
            {
                for (Int32 i = 0; i < dis.Length; i++)
                {
                    len += GetDirectoryLength(dis[i].FullName);
                }
            }
            return len;
        }

        /// <summary>
        /// 获取目录中，所有文件夹中的所有文件的集合
        /// </summary>
        public static List<FileInfo> GetAllFilesFromDirectoryByExtension(String dirPath, string[] arrExtension)
        {
            List<FileInfo> listFiles = new List<FileInfo>();
            //判断给定的路径是否存在,如果不存在则退出
            if (!Directory.Exists(dirPath))
                return null;
            DirectoryInfo dir = new DirectoryInfo(dirPath);

            if (arrExtension.HasValue())
            {
                listFiles = dir.EnumerateFiles().Where(q => arrExtension.Contains(q.Extension.ToLower())).ToList();
            }
            else
            {
                listFiles = dir.EnumerateFiles().ToList();
            }

            DirectoryInfo[] dis = dir.GetDirectories();
            if (dis.Length > 0)
            {
                for (Int32 i = 0; i < dis.Length; i++)
                {
                    listFiles = listFiles.Concat(GetAllFilesFromDirectoryByExtension(dis[i].FullName, arrExtension)).ToList();
                }
            }

            return listFiles;
        }

        /// <summary>
        /// 复制文件夹下的所有数据或第一层数据
        /// </summary>
        /// <param name="srcPath">旧路径</param>
        /// <param name="aimPath">新路径</param>
        /// <param name="type">0:连里面的目录一起复制,1:只复制该目录下的文件</param>
        public static void CopyDir(String srcPath, String aimPath, Int32 type)
        {
            //   检查目标目录是否以目录分割字符结束如果不是则添加之    
            if (aimPath[aimPath.Length - 1] != Path.DirectorySeparatorChar)
                aimPath += Path.DirectorySeparatorChar;
            //   判断目标目录是否存在如果不存在则新建之    
            if (!Directory.Exists(aimPath)) Directory.CreateDirectory(aimPath);

            String[] fileList;
            if (type == 1)//如果你指向copy目标文件下面的文件而不包含目录请使用下面的方法
            {
                fileList = Directory.GetFiles(srcPath);
            }
            else//得到源目录的文件列表，该里面是包含文件以及目录路径的一个数组
            {
                fileList = Directory.GetFileSystemEntries(srcPath);
            }
            //   遍历所有的文件和目录    
            foreach (String file in fileList)
            {
                //   先当作目录处理如果存在这个目录就递归Copy该目录下面的文件    
                if (Directory.Exists(file))
                    CopyDir(file, aimPath + Path.GetFileName(file), type);
                //   否则直接Copy文件    
                else
                    File.Copy(file, aimPath + Path.GetFileName(file), true);
            }
        }

        /// <summary>
        /// 从路径里获得文件名
        /// </summary>
        /// <param name="url">文件路径</param>
        /// <returns>文件名</returns>
        public static String GetFileName(String url)
        {
            Int32 lastindex = 0;
            String filename = "";
            if (url.Split('/').Length != -1)//如果是用'/'分割路径
            {
                lastindex = url.Split('/').Length;
                filename = url.Split('/')[lastindex - 1];

            }
            else if (url.Split('\\').Length != -1)//如果是用'\\'分割路径
            {
                lastindex = url.Split('\\').Length;
                filename = url.Split('\\')[lastindex - 1];
            }
            return filename;

        }

        /// <summary>
        /// 重命名文件或文件夹名
        /// </summary>
        /// <param name="oldname">旧名称</param>
        /// <param name="newname">新名称</param>
        /// <param name="url">不包括文件名</param>
        /// <param name="type">file:文件 directory:文件夹</param>
        public static void ChangeFileName(String url, String oldname, String newname, String type)
        {
            switch (type.ToLower())
            {
                case "file":
                    {
                        if (File.Exists(url + "\\" + newname))
                        {
                            newname += "(重命名)";
                        }
                        File.Move(url + "\\" + oldname, url + "\\" + newname);
                        break;
                    }
                case "directory":
                    {
                        if (Directory.Exists(url + "\\" + newname))
                        {
                            newname += "(重命名)";
                        }
                        Directory.Move(url + "\\" + oldname, url + "\\" + newname);
                        break;
                    }
                default:
                    break;
            }
        }

        /// <summary>
        /// 去掉文件只读属性,并删除该文件夹及其下所有文件
        /// </summary>
        /// <param name="dir">文件夹绝对路径</param>
        public static void DeleteDirectory(String dir)
        {
            try
            {
                if (Directory.Exists(dir))
                {
                    FileInfo[] files = new DirectoryInfo(dir).GetFiles();
                    foreach (FileInfo str in files)
                    {
                        DeleteFile(str.FullName);
                        System.Threading.Thread.Sleep(1000);
                    }

                    DirectoryInfo[] dirs = new DirectoryInfo(dir).GetDirectories();
                    if (dirs.Length > 0)
                    {
                        foreach (DirectoryInfo d in dirs)
                        {
                            DeleteDirectory(d.FullName);
                        }
                    }
                    Directory.Delete(dir, true);
                }
            }
            catch
            {

            }
        }

        /// <summary>
        /// 去掉文件只读属性,并删除该文件夹下所有文件
        /// </summary>
        /// <param name="dir">文件夹绝对路径</param>
        public static void DeleteFiles(String dir)
        {
            if (Directory.Exists(dir))
            {
                FileInfo[] files = new DirectoryInfo(dir).GetFiles();
                foreach (FileInfo str in files)
                {
                    DeleteFile(str.FullName);
                }
            }
        }

        /// <summary>
        /// 去掉文件只读属性,并删除该文件
        /// </summary>
        /// <param name="dir">文件绝对路径</param>
        public static void DeleteFile(String dir)
        {
            if (File.Exists(dir))
            {
                FileInfo file = new FileInfo(dir);
                if ((file.Attributes & FileAttributes.ReadOnly) != 0)
                {
                    file.Attributes &= ~FileAttributes.ReadOnly;
                }
                try
                {//某些时候会出现文件拒绝访问的情况
                    File.Delete(dir);
                }
                catch
                {//延迟一段时间后再次尝试删除
                    System.Threading.Thread.Sleep(5000);
                    File.Delete(dir);
                }
            }
        }

        /// <summary>
        /// 新建文件夹,不管有多少层不存在,都会全部一起建立
        /// </summary>
        /// <param name="dir">目的路径</param>
        public static void CreateDir(String dir)
        {
            String[] i = null;
            String dirs = "";
            dir.Replace("\\", "/");

            i = dir.Split('/');

            foreach (String p in i)
            {
                if (p.Length > 0)
                {
                    dirs = dirs + (p + "\\");

                    if (!Directory.Exists(dirs))
                    {
                        Directory.CreateDirectory(dirs);
                    }
                }
            }

        }

        /// <summary>
        /// 新建一个文件到指定位置
        /// </summary>
        /// <param name="dirPath">文件存放文件夹绝对路径,请确保以分隔符结尾</param>
        /// <param name="fileName">文件名</param>
        /// <param name="context">文件内容</param>
        /// <param name="reName">true:覆盖原来的文件 false:重命名 "":不新建</param>
        public static XJsonInfo CreateFile(string dirPath, string fileName, string context, string reName)
        {
            if (!Directory.Exists(dirPath))
            {
                CreateDir(dirPath);
            }

            string filePath = dirPath + "\\" + fileName;
            if (File.Exists(filePath) && reName == "")
            {
                return new XJsonInfo(false, "文件已存在");
            }
            else if (File.Exists(filePath) && reName == "false")
            {
                int r = 1;
                string newDirPath = dirPath + Path.GetFileNameWithoutExtension(filePath) + r.ToString();
                while (File.Exists(newDirPath))
                {
                    r++;
                    newDirPath = dirPath + Path.GetFileNameWithoutExtension(filePath) + r.ToString();
                }
                filePath = newDirPath;
            }
            try
            {
                FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
                StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.GetEncoding("utf-8"));//通过指定字符编码方式可以实现对汉字的支持，否则在用记事本打开查看会出现乱码
                sw.Flush();
                sw.BaseStream.Seek(0, SeekOrigin.Begin);
                sw.WriteLine(context);
                sw.Flush();
                sw.Close();
                return new XJsonInfo().SetData(Path.GetFileName(filePath));
            }
            catch(Exception ex)
            {
                return new XJsonInfo(false, ex.Message);
            }
        }

        public static XJsonInfo CreateFile(String filePath, Stream stream, Boolean cover = true)
        {
            FileMode fmode = FileMode.Create;
            if (!File.Exists(filePath) || cover)
            {
                fmode = FileMode.Create;
            }
            else if (File.Exists(filePath) && cover == false)
            {
                fmode = FileMode.Append;
            }

            try
            {
                // 把 Stream 转换成 byte[] 
                byte[] bytes = new byte[stream.Length];
                stream.Read(bytes, 0, bytes.Length);
                // 设置当前流的位置为流的开始 
                stream.Seek(0, SeekOrigin.Begin);

                // 把 byte[] 写入文件 
                using (var fs = new FileStream(filePath, fmode))
                {
                    using (var bw = new BinaryWriter(fs))
                    {
                        bw.Write(bytes);
                        stream.Dispose();
                        stream.Close();
                        return new XJsonInfo();
                    }
                }

            }
            catch (Exception ex)
            {
                return new XJsonInfo(false, ex.Message);
            }
        }

        /// <summary>
        /// 读取文件，如果不存在则创建
        /// </summary>
        /// <param name="filepath">文件路径</param>
        /// <param name="unicode">编码（默认uft-8）</param>
        /// <param name="create">true:不存在文件则创建 false：不创建（默认false）</param>
        /// <returns></returns>
        public static string ReadTextFileDate(string filepath, string unicode = "utf-8", bool create = false)
        {
            string strInput = "";

            if (File.Exists(filepath))
            {
                StreamReader sr = new StreamReader(filepath, UnicodeEncoding.GetEncoding(unicode));
                strInput = sr.ReadToEnd();
                sr.Close();
            }
            else
            {
                if (create)
                {
                    var dirPath = Path.GetDirectoryName(filepath);
                    CreateDir(dirPath);
                    StreamWriter SW;
                    SW = File.CreateText(filepath);
                    SW.Close();
                }
            }
            return strInput;
        }
        /// <summary>
        /// 修改中的内容，路径不存在会自动创建
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="StrCount">内容</param>
        /// <param name="create">true:覆盖原来的文件 false:重命名 "":不新建</param>
        public static void WriteTextFile(string filePath, string StrCount, string create)
        {
            if (File.Exists(filePath))
            {
                //System.IO.StreamReader sr = new System.IO.StreamReader(filePath);
                //string s = sr.ReadToEnd();
                //sr.Close();
                //s = s.Replace(s, StrCount);
                System.IO.StreamWriter sw = new System.IO.StreamWriter(filePath, false);
                sw.Write(StrCount);
                sw.Close();
            }
            else
            {
                CreateFile(Path.GetDirectoryName(filePath), Path.GetFileName(filePath), StrCount, create);
            }
        }

        /// <summary>
        /// 添加文件或文件夹到新的压缩包
        /// </summary>
        /// <param name="listFilePaths">文件或文件夹绝对路径集合</param>
        /// <param name="saveTo">压缩包保存到的路径（包括压缩包文件名）</param>
        /// <param name="passWord">加密密码</param>
        /// <returns></returns>
        public static string ToZip(List<string> listFilePaths, string saveTo, string passWord = null)
        {
            try
            {
                using (ZipFile zip = new ZipFile(System.Text.Encoding.UTF8))
                {
                    if (!String.IsNullOrWhiteSpace(passWord))
                        zip.Password = passWord;

                    zip.StatusMessageTextWriter = System.Console.Out;
                    foreach (string path in listFilePaths)
                    {
                        if (File.Exists(path))
                            zip.AddFile(path, new DirectoryInfo(Path.GetDirectoryName(path)).Name);
                        else if (Directory.Exists(path))
                            zip.AddDirectory(path, new DirectoryInfo(path).Name);
                    }

                    string saveDir = Path.GetDirectoryName(saveTo);
                    if (!Directory.Exists(saveDir))
                        Directory.CreateDirectory(saveDir);

                    zip.Save(saveTo);
                }
                return "";
            }
            catch (Exception ex1)
            {
                return ex1.Message;
            }
        }

        /// <summary>
        /// 解压指定路径的压缩文件到特定目录，覆盖原来的文件
        /// </summary>
        /// <param name="zipPath">压缩包绝对路径</param>
        /// <param name="extractTo">解压到的文件夹绝对路径，没有则自动创建</param>
        /// <param name="passWord">解压密码</param>
        /// <returns></returns>
        public static string FromZip(string zipPath, string extractTo, string passWord = null)
        {
            try
            {
                using (ZipFile zip = new ZipFile(zipPath, System.Text.Encoding.UTF8))
                {
                    string exDir = Path.GetDirectoryName(extractTo);
                    if (!Directory.Exists(exDir))
                        Directory.CreateDirectory(exDir);
                    if (!String.IsNullOrWhiteSpace(passWord))
                        zip.Password = passWord;
                    zip.ExtractAll(extractTo, ExtractExistingFileAction.OverwriteSilently);
                }
                return "";
            }
            catch (Exception ex1)
            {
                return ex1.Message;
            }
        }

        #region 复制文件
        /// <summary>
        /// 复制
        /// </summary>
        /// <param name="dirPath">文件存放文件夹绝对路径,请确保以分隔符结尾</param>
        /// <param name="fileName">文件名称</param>
        /// <param name="suffix">如果已存在，原文件追加的后缀名,不需要加点号</param>
        /// <param name="newFileName">新文件名称</param>
        public static void CopyFile(String dirPath, String fileName, String suffix = "重命名", String newFileName = null)
        {
            dirPath = AdditionalDelimiter(dirPath);
            String filePath = dirPath + fileName;
            if (Directory.Exists(dirPath) && File.Exists(filePath))
            {
                if (String.IsNullOrWhiteSpace(newFileName))
                    newFileName = fileName + "." + suffix;
                File.Copy(filePath, dirPath + newFileName);
            }

        }
        #endregion
    }
}
